﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

#if CF_1_0 || CF_2_0
using RaisingStudio.Core;
#endif

namespace RaisingStudio.Data.Linq
{
    public static class ExpressionDataExtension
    {
        public static ExpressionData<T, S> Where<T, S>(this ExpressionData<T, S> source, Expression<Func<T, RaisingStudio.Data.Expressions.ConditionExpression>> predicate)
        {
#if CF_1_0 || CF_2_0
            return (new ExpressionData<T, S>(source.DataContext, source.Value, source.Table, (predicate.Compile()).DynamicInvoke(source.Value) as RaisingStudio.Data.Expressions.ConditionExpression, source.Columns));
#else
           return (new ExpressionData<T, S>(source.DataContext, source.Value, source.Table, (predicate.Compile())(source.Value), source.Columns));
#endif
        }


        public static ExpressionData<T, S> OrderBy<T, S>(this ExpressionData<T, S> source, Expression<Func<T, RaisingStudio.Data.Expressions.ColumnExpression>> predicate)
        {
            RaisingStudio.Data.Expressions.ColumnExpression column = CommandBuilder.GetColumnExpression(predicate);
            if (((object)column) != null)
            {
                RaisingStudio.Data.Expressions.ConditionExpression condition = null;
                if (source.Condition != null)
                {
                    condition = source.Condition.OrderBy(column);
                }
                else
                {
                    condition = new RaisingStudio.Data.Expressions.ConditionExpression(new RaisingStudio.Data.Expressions.SortingExpression(column));
                }
                return (new ExpressionData<T, S>(source.DataContext, source.Value, source.Table, condition, source.Columns));
            }
            return source;
        }

        public static ExpressionData<T, S> OrderByDescending<T, S>(this ExpressionData<T, S> source, Expression<Func<T, RaisingStudio.Data.Expressions.ColumnExpression>> predicate)
        {
            RaisingStudio.Data.Expressions.ColumnExpression column = CommandBuilder.GetColumnExpression(predicate);
            if (((object)column) != null)
            {
                RaisingStudio.Data.Expressions.ConditionExpression condition = null;
                if (source.Condition != null)
                {
                    condition = source.Condition.OrderBy(column, RaisingStudio.Data.Expressions.SortingDirection.Descending);
                }
                else
                {
                    condition = new RaisingStudio.Data.Expressions.ConditionExpression(new RaisingStudio.Data.Expressions.SortingExpression(column, RaisingStudio.Data.Expressions.SortingDirection.Descending));
                }
                return (new ExpressionData<T, S>(source.DataContext, source.Value, source.Table, condition, source.Columns));
            }
            return source;
        }

        public static ExpressionData<T, S> ThenBy<T, S>(this ExpressionData<T, S> source, Expression<Func<T, RaisingStudio.Data.Expressions.ColumnExpression>> predicate)
        {
            RaisingStudio.Data.Expressions.ColumnExpression column = CommandBuilder.GetColumnExpression(predicate);
            if (((object)column) != null)
            {
                RaisingStudio.Data.Expressions.ConditionExpression condition = null;
                if (source.Condition != null)
                {
                    condition = source.Condition.OrderBy(column);
                }
                else
                {
                    condition = new RaisingStudio.Data.Expressions.ConditionExpression(new RaisingStudio.Data.Expressions.SortingExpression(column));
                }
                return (new ExpressionData<T, S>(source.DataContext, source.Value, source.Table, condition, source.Columns));
            }
            return source;
        }

        public static ExpressionData<T, S> ThenByDescending<T, S>(this ExpressionData<T, S> source, Expression<Func<T, RaisingStudio.Data.Expressions.ColumnExpression>> predicate)
        {
            RaisingStudio.Data.Expressions.ColumnExpression column = CommandBuilder.GetColumnExpression(predicate);
            if (((object)column) != null)
            {
                RaisingStudio.Data.Expressions.ConditionExpression condition = null;
                if (source.Condition != null)
                {
                    condition = source.Condition.OrderBy(column, RaisingStudio.Data.Expressions.SortingDirection.Descending);
                }
                else
                {
                    condition = new RaisingStudio.Data.Expressions.ConditionExpression(new RaisingStudio.Data.Expressions.SortingExpression(column, RaisingStudio.Data.Expressions.SortingDirection.Descending));
                }
                return (new ExpressionData<T, S>(source.DataContext, source.Value, source.Table, condition, source.Columns));
            }
            return source;
        }


        public static ExpressionData<T, S> Select<T, S>(this ExpressionData<T, S> source, Expression<Func<T, object>> predicate)
        {
            RaisingStudio.Data.Expressions.ColumnExpression[] columns = null;
            if ((predicate is LambdaExpression) && ((predicate as LambdaExpression).Body.NodeType == ExpressionType.Call))
            {
#if CF_1_0 || CF_2_0
                object o = ((predicate.Compile()).DynamicInvoke(source.Value));
#else
                object o = ((predicate.Compile())(source.Value));
#endif
                if (o is RaisingStudio.Data.Expressions.ColumnExpressionCollection)
                {
                    columns = (RaisingStudio.Data.Expressions.ColumnExpression[])(o as RaisingStudio.Data.Expressions.ColumnExpressionCollection);
                }
                else if (o is RaisingStudio.Data.Expressions.ColumnExpression[])
                {
                    columns = (o as RaisingStudio.Data.Expressions.ColumnExpression[]);
                }
                else if (o is RaisingStudio.Data.Expressions.ColumnExpression)
                {
                    columns = new RaisingStudio.Data.Expressions.ColumnExpression[] { o as RaisingStudio.Data.Expressions.ColumnExpression };
                }
                else
                {
                    // TODO:
                }
            }
            else
            {
                columns = CommandBuilder.GetColumnExpressions(predicate);
            }
            if (columns != null)
            {
                RaisingStudio.Data.Expressions.ColumnExpressionCollection columnCollection = null;
                if (source.Columns != null)
                {
                    columnCollection = new RaisingStudio.Data.Expressions.ColumnExpressionCollection(source.Columns);
                    columnCollection.AddRange(columns);
                }
                else
                {
                    columnCollection = new RaisingStudio.Data.Expressions.ColumnExpressionCollection(columns);
                }
                return (new ExpressionData<T, S>(source.DataContext, source.Value, source.Table, source.Condition, columnCollection));
            }
            return source;
        }
    }
}
